#include "stm32f10x.h"                  // Device header

/*引脚配置层*/

/**
  * 函    数：SPI写SS引脚电平
  * 参    数：BitValue 协议层传入的当前需要写入SS的电平，范围0~1
  * 返 回 值：无
  * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置SS为低电平，当BitValue为1时，需要置SS为高电平
  */
void MySPI_W_SS(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)BitValue);		//根据BitValue，设置SS引脚的电平
}

/**
  * 函    数：SPI写SCK引脚电平
  * 参    数：BitValue 协议层传入的当前需要写入SCK的电平，范围0~1
  * 返 回 值：无
  * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置SCK为低电平，当BitValue为1时，需要置SCK为高电平
  */
void MySPI_W_SCK(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)BitValue);		//根据BitValue，设置SCK引脚的电平
}

/**
  * 函    数：SPI写MOSI引脚电平
  * 参    数：BitValue 协议层传入的当前需要写入MOSI的电平，范围0~1
  * 返 回 值：无
  * 注意事项：此函数需要用户实现内容，当BitValue为0时，需要置MOSI为低电平，当BitValue为1时，需要置MOSI为高电平
  */
void MySPI_W_MOSI(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)BitValue);		//根据BitValue，设置MOSI引脚的电平，BitValue要实现非0即1的特性
}

/**
  * 函    数：I2C读MISO引脚电平
  * 参    数：无
  * 返 回 值：协议层需要得到的当前MISO的电平，范围0~1
  * 注意事项：此函数需要用户实现内容，当前MISO为低电平时，返回0，当前MISO为高电平时，返回1
  */
uint8_t MySPI_R_MISO(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);			//读取MISO电平并返回
}

//初始化
void MySPI_Init(void)
{
	/*开启时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA4、PA5和PA7引脚初始化为推挽输出
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//将PA6引脚初始化为上拉输入
	
	/*设置默认电平*/
	MySPI_W_SS(1);											//SS默认高电平
	MySPI_W_SCK(0);											//SCK默认低电平
}
//SPI的3个时序基本单元
//
//起始
void MySPI_Start(void)
{
	MySPI_W_SS(0);				//拉低SS，开始时序
}
//结束
void MySPI_Stop(void)
{
	MySPI_W_SS(1);				//拉高SS，终止时序
}
//交换一个字节
//由图中看到当SS下降沿后，SCK下降沿才数据移出，是有先来后到的
//对于硬件来说，由于硬件的移位寄存器电路，这两个操作是同时发生的
//对于软件来说，程序是一条条执行的，所以只能由先来后到的逻辑：先SS下降沿，再移出数据；再SCK上升沿，再移入数据；再SCK下降沿，再移出数据

////优化：利用移位的特性，但是ByteSend本身被修改无法回到之前
//uint8_t MySPI_SwapByte(uint8_t ByteSend){
//	for(uint8_t i=0;i<8;i++){
//			//先SS下降沿，再移出数据：主机的最高位&0x80，移出到MOSI中，从机的最高位移出到MISO中，从机不需要管
//			MySPI_W_MOSI(ByteSend&0x80);
//	  	ByteSend<<=1;//把ByteSend移到最高位到MOSI，那最低位会被补0，所以不需要ByteReceive
//		
//			//再SCK上升沿，再移入数据：主机和从机同时移入数据，主机需要读取MISO中的数据
//			MySPI_W_SCK(1);
//			if(MySPI_R_MISO()==1){
//				ByteSend|=0x01;
//			}
//			MySPI_W_SCK(0);
//			//再SCK上升沿，再移入数据
//	}

//	return ByteSend;
//}



//使用掩码来依次提取数据——本次实验使用-默认模式0 ：切换不同的模式，根据不同的模式时序来更换引脚电平的变化即可
uint8_t MySPI_SwapByte(uint8_t ByteSend){
	uint8_t i,ByteReceive=0x00;
	for(i=0;i<8;i++){
			//先SS下降沿，再移出数据：主机的最高位&0x80，移出到MOSI中，从机的最高位移出到MISO中，从机不需要管
			MySPI_W_MOSI(!!(ByteSend & (0x80 >> i)));	
			//再SCK上升沿，再移入数据：主机和从机同时移入数据，主机需要读取MISO中的数据
			MySPI_W_SCK(1);
			if (MySPI_R_MISO()){ByteReceive |= (0x80 >> i);}	
			MySPI_W_SCK(0);
			//再SCK上升沿，再移入数据
	}

	return ByteReceive;
}


